/*
 * RTSAI - Real-Time Strategy engine for AI research
 * Copyright(C) 2006 DIMAp-UFRN, licensed under LGPL
 *
 * Unit implementation ( Unit.cpp )
 */

#ifndef UNIT_CPP_
#define UNIT_CPP_

// INCLUDES ===================================================================
#include <string>
#include "Log.h"
#include "Unit.h"
#include "UnitState.h"
#include "Player.h"
#include "GameObject.h"

// IMPLEMENTATIONS ============================================================
// PUBLIC METHODS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Constructor
/*! Default constructor
 */
Unit :: Unit ()
{
    state = NULL;

    setSpeed (5);             // speed along Forward direction.
    setMaxForce (5.0);        // steering force is clipped to this magnitude
    setMaxSpeed (5.0);        // velocity is clipped to this magnitude
}


// void -----------------------------------------------------------------------
/*! Just resets the attributes of this object (Implementation for a pure
 *  virtual method)
 */
void Unit :: reset () { /* Empty */ }

/*! Handle the received messages and perform an action. This method just
 *  call the corresponding methods in the unit state.
 */
Action* Unit :: act ()
{
    if ( mbox.size() > 0 )
    {
        state -> on_message ( mbox );  // handle messages
        mbox.clear();                  // and clear them
    }

    if (state)
        return state -> act();
    return NULL;
}


bool Unit :: predictCollision ( const GameObject &obj,
                                    const Vec3& force,
                                    const float predictionTime )
{
    Vector3D new_pos = predictFuturePosition ( force, predictionTime );
    return obj.collideWithSphere ( new_pos, radius() );
}


/*! This method just changes the actual state
 */
void Unit :: change_state ( UnitState *new_state )
{
    if ( state ) {
        state -> on_exit();
        delete state;
    }

    state = new_state;

    if ( state ) {
        state -> unit = this;
        state -> on_enter();
    }
}


// message related methods --------------------------------------------


int Unit :: sendMessage ( MessageReceiver *receiver, Message::Performative perf, string content )
{
    Message *msg = new Message ( this, receiver, perf, content );
    return msg -> get_conversation_id ();
}


int Unit :: call_for_proposal ( string cnt )
{
    Message *msg = new Message ( this,
                                 player,
                                 Message::CALL_FOR_PROPOSAL, cnt );
    return msg -> get_conversation_id ();
}

/*! Answers according to received message
 */
int Unit :: answer ( Message *msg, Message::Performative perf, string content )
{
    int id = msg->get_conversation_id();
    new Message ( id, this, msg->get_sender(), perf, content );
    return id;
}


int Unit :: broadcastMessage ( Message::Performative perf, string content )
{
    Message *msg = new Message ( this, player, perf, content );
    return msg->get_conversation_id();
}


// Destructor
/*! Default destructor
 */
Unit :: ~Unit ()
{
    // TODO: delete vehicle
}


Vector3D Unit :: steerToAvoidObject (float timeToCollision, const GameObject& obj) const
{
    return obj.steerToAvoid (*this, timeToCollision);
}


Vector3D Unit :: steerToAvoidObjects (float timeToCollision, const ObjectList& objs) const
{
    Vector3D avoidance;

    foreach_const ( o, objs )
        avoidance += steerToAvoidObject ( timeToCollision, (**o) );

    return avoidance;
}





#endif // UNIT_CPP_
